package com.example.service.impl;

import com.example.annotation.RateLimit;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import com.example.util.PasswordUtils;
import com.example.util.RedisUtils;
import com.example.util.SmsUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.ValidationException;
import java.util.Random;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;

@Service
public class UserServiceImpl implements UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private SmsUtils smsUtils;

    @Autowired
    private UserMapper userMapper;

    private static final String REGISTER_CODE_PREFIX = "sms:register:";
    private static final String LOGIN_CODE_PREFIX = "sms:login:";
    private static final String RESET_CODE_PREFIX = "sms:reset:";
    private static final String RESET_TOKEN_PREFIX = "reset:token:";
    private static final long CODE_EXPIRE = 300; // 验证码有效期5分钟
    private static final long RESET_TOKEN_EXPIRE = 1800; // 重置令牌有效期30分钟

    // 雪花算法实例，workerId=1, datacenterId=1，可根据实际部署调整
    private static final Snowflake snowflake = IdUtil.getSnowflake(1, 1);

    @Override
    @RateLimit(limit = 5, period = 300) // 5分钟内最多发送5次验证码
    public boolean sendRegisterCode(String phone) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        // 检查手机号是否已注册
        if (checkPhoneExists(phone)) {
            throw new ValidationException("该手机号已注册");
        }

        // 生成6位随机验证码
        String code = RandomStringUtils.randomNumeric(6);
        logger.info("发送注册验证码到手机号: {}, 验证码: {}", phone, code);
        
        // 只传递code，不拼接中文
        boolean success = smsUtils.sendRegisterSms(phone, code);
        if (success) {
            // 将验证码存入Redis
            redisUtils.set(REGISTER_CODE_PREFIX + phone, code, CODE_EXPIRE);
        }
        return success;
    }

    @Override
    @RateLimit(limit = 5, period = 300) // 5分钟内最多发送5次验证码
    public boolean sendLoginCode(String phone) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        // 检查手机号是否已注册
        if (!checkPhoneExists(phone)) {
            throw new ValidationException("该手机号未注册");
        }

        // 生成6位随机验证码
        String code = RandomStringUtils.randomNumeric(6);
        logger.info("发送登录验证码到手机号: {}, 验证码: {}", phone, code);
        
        // 只传递code，不拼接中文
        boolean success = smsUtils.sendLoginSms(phone, code);
        if (success) {
            // 将验证码存入Redis
            redisUtils.set(LOGIN_CODE_PREFIX + phone, code, CODE_EXPIRE);
        }
        return success;
    }
    
    @Override
    @RateLimit(limit = 5, period = 300) // 5分钟内最多发送5次验证码
    public boolean sendResetCode(String phone) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        // 检查手机号是否已注册
        if (!checkPhoneExists(phone)) {
            throw new ValidationException("该手机号未注册");
        }

        // 生成6位随机验证码
        String code = RandomStringUtils.randomNumeric(6);
        logger.info("发送重置密码验证码到手机号: {}, 验证码: {}", phone, code);
        
        // 只传递code，不拼接中文
        boolean success = smsUtils.sendResetSms(phone, code);
        if (success) {
            // 将验证码存入Redis
            redisUtils.set(RESET_CODE_PREFIX + phone, code, CODE_EXPIRE);
        }
        return success;
    }

    @Override
    @Transactional
    public User loginByCode(String phone, String code) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        String savedCode = redisUtils.get(LOGIN_CODE_PREFIX + phone);
        if (savedCode != null && savedCode.equals(code)) {
            // 验证码正确，删除验证码
            redisUtils.delete(LOGIN_CODE_PREFIX + phone);
            
            // 查询用户信息
            User user = userMapper.findByPhone(phone);
            if (user == null) {
                throw new ValidationException("用户不存在");
            }
            
            // 检查用户状态
            if (!user.getIsActive()) {
                throw new ValidationException("账号已被禁用");
            }
            
            logger.info("用户验证码登录成功: {}", phone);
            return user;
        }
        logger.warn("用户验证码登录失败: {}, 验证码: {}", phone, code);
        throw new ValidationException("验证码错误或已过期");
    }

    @Override
    public User loginByPassword(String phone, String password) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        User user = userMapper.findByPhone(phone);
        if (user == null) {
            throw new ValidationException("用户不存在");
        }
        
        // 检查用户状态
        if (!user.getIsActive()) {
            throw new ValidationException("账号已被禁用");
        }
        
        if (PasswordUtils.matches(password, user.getHashedPassword())) {
            logger.info("用户密码登录成功: {}", phone);
            return user;
        }
        
        logger.warn("用户密码登录失败: {}", phone);
        throw new ValidationException("手机号或密码错误");
    }

    @Override
    @Transactional
    public boolean register(User user) {
        // 验证手机号格式
        if (!user.getPhone().matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        // 验证密码强度
        if (user.getPassword() == null || user.getPassword().length() < 6) {
            throw new ValidationException("密码长度不能小于6位");
        }
        
        // 验证验证码
        String savedCode = redisUtils.get(REGISTER_CODE_PREFIX + user.getPhone());
        if (savedCode == null || !savedCode.equals(user.getCode())) {
            throw new ValidationException("验证码错误或已过期");
        }
        
        // 检查手机号是否已注册
        if (checkPhoneExists(user.getPhone())) {
            throw new ValidationException("该手机号已注册");
        }
        
        // 删除验证码
        redisUtils.delete(REGISTER_CODE_PREFIX + user.getPhone());
        
        // 设置用户属性
        user.setId(generateId());
        user.setHashedPassword(PasswordUtils.encode(user.getPassword()));
        user.setIsActive(true);
        user.setIsSuperuser(false);
        user.setIsPhoneVerified(true);
        user.setIsEmailVerified(false);
        
        // 保存用户信息
        int result = userMapper.insert(user);
        logger.info("用户注册成功: {}", user.getPhone());
        return result > 0;
    }
    
    @Override
    public boolean verifyResetRequest(String phone, String code) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        // 检查手机号是否已注册
        if (!checkPhoneExists(phone)) {
            throw new ValidationException("该手机号未注册");
        }
        
        // 验证验证码
        String savedCode = redisUtils.get(RESET_CODE_PREFIX + phone);
        if (savedCode == null || !savedCode.equals(code)) {
            throw new ValidationException("验证码错误或已过期");
        }
        
        // 删除验证码
        redisUtils.delete(RESET_CODE_PREFIX + phone);
        
        // 生成重置令牌
        String resetToken = RandomStringUtils.randomAlphanumeric(32);
        redisUtils.set(RESET_TOKEN_PREFIX + phone, resetToken, RESET_TOKEN_EXPIRE);
        
        logger.info("验证重置密码请求成功: {}", phone);
        return true;
    }
    
    @Override
    public boolean resetPassword(String phone, String newPassword) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        // 验证密码强度
        if (newPassword == null || newPassword.length() < 6) {
            throw new ValidationException("密码长度不能小于6位");
        }
        
        // 检查重置令牌
        String resetToken = redisUtils.get(RESET_TOKEN_PREFIX + phone);
        if (resetToken == null) {
            throw new ValidationException("重置请求已过期，请重新验证");
        }
        
        // 删除重置令牌
        redisUtils.delete(RESET_TOKEN_PREFIX + phone);
        
        // 更新密码
        String hashedPassword = PasswordUtils.encode(newPassword);
        int result = userMapper.updatePassword(phone, hashedPassword);
        
        logger.info("用户重置密码成功: {}", phone);
        return result > 0;
    }
    
    @Override
    public boolean checkPhoneExists(String phone) {
        return userMapper.checkPhoneExists(phone) > 0;
    }
    
    @Override
    public boolean logout(Long userId) {
        // 这里可以添加登出逻辑，例如清除会话等
        logger.info("用户退出登录: {}", userId);
        return true;
    }
    
    @Override
    @Transactional
    public boolean unregister(String phone, String password) {
        // 验证手机号格式
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            throw new ValidationException("手机号格式不正确");
        }
        
        // 查询用户信息
        User user = userMapper.findByPhone(phone);
        if (user == null) {
            throw new ValidationException("用户不存在");
        }
        
        // 验证密码
        if (!PasswordUtils.matches(password, user.getHashedPassword())) {
            throw new ValidationException("密码错误");
        }
        
        // 注销用户（设置为非活动状态）
        int result = userMapper.deactivateUser(user.getId());
        logger.info("用户注销成功: {}", phone);
        return result > 0;
    }
    
    /**
     * 生成ID（简单实现，实际应用中可能需要更复杂的ID生成策略）
     */
    private Long generateId() {
        return snowflake.nextId();
    }
} 